package com.scau.XFourPOS.dao.impl;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.hibernate.metadata.ClassMetadata;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.stereotype.Repository;
import org.springframework.util.Assert;

import com.scau.XFourPOS.dao.BaseDao;
import com.scau.XFourPOS.utils.PageUtils;
import com.scau.XFourPOS.utils.StringUtils;


/**
 * 类名称：BaseDaoImpl<T> 类描述：dao泛型类，实现了泛型接口，所有的dao类都继承这个类，实现基本的CRUD操作和简单的分页操作.
 * 创建人：庄祥鹏
 * */
public class BaseDaoImpl<T> implements BaseDao<T> {
	
	@Autowired
	private SessionFactory sessionFactory;
	private Class<T> entityClass;

	@SuppressWarnings("unchecked")
	public BaseDaoImpl() {
		// 就是要获取E的真实数据类型
		this.entityClass = (Class<T>) ((ParameterizedType) this.getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];

	}
	/**
	 * 用于用于省略Dao层, 在Service层直接使用通用BaseDaoImpl的构造函数.
	 * 在构造函数中定义对象类型Class.
	 * eg.
	 * BaseDaoImpl<User> userDao = new BaseDaoImpl<User>(sessionFactory, User.class);
	 */
	public BaseDaoImpl(final SessionFactory sessionFactory, final Class<T> entityClass) {
		this.sessionFactory = sessionFactory;
		this.entityClass = entityClass;
	}
	/**
	 * 取得当前Session.
	 * @return Session
	 */
	public Session getSession() {
		return sessionFactory.getCurrentSession();
	}

	/**
	 * 保存或修改.
	 * @param entity
	 */
	public void saveOrUpdateEntity(T entity) {
		getSession().saveOrUpdate(entity);
	}

	/**
	 * 删除对象.
	 * @param entity 对象必须是session中的对象或含id属性的transient对象.
	 */
	public void deleteEntity(T entity) {
		getSession().delete(entity);
	}
	/**
	 * 按id删除对象.
	 * @param id
	 */
	public void deleteEntityById(Serializable id) {
		deleteEntity(loadEntityById(id));
	}

	/**
	 * 按id获取特定类的对象.
	 * @param id
	 * @param entityClass
	 * @return 对象
	 */
	@SuppressWarnings("unchecked")
	public T loadEntity(final Class<T> entityClass, final Serializable id) {
		return (T) getSession().load(entityClass, id);

	}
	/**
	 * 按id获取对象.
	 * @param id
	 * @return 对象
	 */
	public T loadEntityById(Serializable id) {
		return (T) loadEntity(entityClass, id);
	}
	/**
	 * 按HQL查询对象列表.
	 * @param hql
	 * @param values 数量可变的参数,按顺序绑定.
	 * @return 结果集合
	 */
	public <X> List<X> find(final String hql, final Object... values) {
		return createQuery(hql, values).list();
	}

	/**
	 * 按HQL查询对象列表.
	 * @param hql
	 * @param values 命名参数,按名称绑定.
	 * @return 对象集合
	 */
	public <X> List<X> find(final String hql, final Map<String, ?> values) {
		return createQuery(hql, values).list();
	}

	/**
	 * 按HQL查询唯一对象.
	 * @param hql
	 * @param values 数量可变的参数,按顺序绑定.
	 * @return 对象
	 */
	public <X> X findUnique(final String hql, final Object... values) {
		return (X) createQuery(hql, values).uniqueResult();
	}

	/**
	 * 按HQL查询唯一对象.
	 * @param hql
	 * @param values 命名参数,按名称绑定.
	 * @return 对象
	 */
	public <X> X findUnique(final String hql, final Map<String, ?> values) {
		return (X) createQuery(hql, values).uniqueResult();
	}

	/**
	 * 执行HQL进行批量修改/删除操作.
	 * @param hql
	 * @param values 数量可变的参数,按顺序绑定.
	 * @return 更新记录数.
	 */
	public int batchExecute(final String hql, final Object... values) {
		return createQuery(hql, values).executeUpdate();
	}

	/**
	 * 执行HQL进行批量修改/删除操作.
	 * @param hql
	 * @param values 命名参数,按名称绑定.
	 * @return 更新记录数.
	 */
	public int batchExecute(final String hql, final Map<String, ?> values) {
		return createQuery(hql, values).executeUpdate();
	}
//==================================华丽的分割线，以下为调用的函数=======================================
	/**
	 * 根据查询HQL与参数列表创建Query对象.
	 * @param queryString 
	 * @param values 数量可变的参数,按顺序绑定.
	 * @return Query
	 */
	public Query createQuery(final String queryString, final Object... values) {
		Assert.hasText(queryString, "queryString不能为空");
		Query query = getSession().createQuery(queryString);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(String.valueOf(i), values[i]);
			}
		}
		return query;
	}

	/**
	 * 根据查询HQL与参数列表创建Query对象. 
	 * @param queryString
	 * @param values 命名参数,按名称绑定.
	 * @return Query
	 */
	public Query createQuery(final String queryString, final Map<String, ?> values) {
		Assert.hasText(queryString, "queryString不能为空");
		Query query = getSession().createQuery(queryString);
		if (values != null) {
			query.setProperties(values);
		}
		return query;
	}
	/**
	 * 初始化对象.
	 * 使用load()方法得到的仅是对象Proxy, 在传到View层前需要进行初始化.
	 * 如果传入entity, 则只初始化entity的直接属性,但不会初始化延迟加载的关联集合和属性.
	 * 如需初始化关联属性,需执行:
	 * Hibernate.initialize(user.getRoles())，初始化User的直接属性和关联集合.
	 * Hibernate.initialize(user.getDescription())，初始化User的直接属性和延迟加载的Description属性.
	 */
	public void initProxyObject(Object proxy) {
		Hibernate.initialize(proxy);
	}
	/**
	 * Flush当前Session.
	 */
	public void flush() {
		getSession().flush();
	}
	/**
	 * 为Query添加distinct transformer.
	 * 预加载关联对象的HQL会引起主对象重复, 需要进行distinct处理.
	 * @param query
	 * @return Query
	 */
	public Query distinct(Query query) {
		query.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
		return query;
	}
	/**
	 * 取得对象的主键名.
	 * @return 对象的主键名
	 */
	public String getIdName() {
		ClassMetadata meta = sessionFactory.getClassMetadata(entityClass);
		return meta.getIdentifierPropertyName();
	}
	//==================================================================================
	//**********************************************************************************
	//==================================================================================
	//-- 分页查询函数 --//

		/**
		 * 分页获取全部对象.
		 */
		public PageUtils<T> getAll(final PageUtils<T> page) {
			return findPage(page,"from Product p where p.name=?0","name");
		}

		/**
		 * 按HQL分页查询.
		 * 
		 * @param page 分页参数. 注意不支持其中的orderBy参数.
		 * @param hql hql语句.
		 * @param values 数量可变的查询参数,按顺序绑定.
		 * 
		 * @return 分页查询结果, 附带结果列表及所有查询输入参数.
		 */
		public PageUtils<T> findPage(final PageUtils<T> page, final String hql, final Object... values) {
			Assert.notNull(page, "page不能为空");
			Query q = createQuery(hql, values);
			if (page.isAutoCount()) {
				long totalCount = countHqlResult(hql, values);
				page.setTotalCount(totalCount);
			}
			setPageParameterToQuery(q, page);
			List result = q.list();
			page.setResult(result);
			return page;
		}
		/**
		 * 按HQL分页查询.
		 * 
		 * @param page 分页参数. 注意不支持其中的orderBy参数.
		 * @param hql hql语句.
		 * @param values 命名参数,按名称绑定.
		 * 
		 * @return 分页查询结果, 附带结果列表及所有查询输入参数.
		 */
		@SuppressWarnings({ "unchecked", "rawtypes" })
		public PageUtils<T> findPage(final PageUtils<T> page, final String hql, final Map<String, ?> values) {
			Assert.notNull(page, "page不能为空");
			Query q = createQuery(hql, values);
			if (page.isAutoCount()) {
				long totalCount = countHqlResult(hql, values);
				page.setTotalCount(totalCount);
			}
			setPageParameterToQuery(q, page);
			List result = q.list();
			page.setResult(result);
			return page;
		}
		/**
		 * 执行count查询获得本次Hql查询所能获得的对象总数.
		 * 
		 * 本函数只能自动处理简单的hql语句,复杂的hql查询请另行编写count语句查询.
		 */
		protected long countHqlResult(final String hql, final Object... values) {
			String countHql = prepareCountHql(hql);
			try {
				Long count = findUnique(countHql, values);
				return count;
			} catch (Exception e) {
				throw new RuntimeException("hql can't be auto count, hql is:" + countHql, e);
			}
		}
		/**
		 * 执行count查询获得本次Hql查询所能获得的对象总数.
		 * 
		 * 本函数只能自动处理简单的hql语句,复杂的hql查询请另行编写count语句查询.
		 */
		protected long countHqlResult(final String hql, final Map<String, ?> values) {
			String countHql = prepareCountHql(hql);
			try {
				Long count = findUnique(countHql, values);
				return count;
			} catch (Exception e) {
				throw new RuntimeException("hql can't be auto count, hql is:" + countHql, e);
			}
		}
		private String prepareCountHql(String orgHql) {
			String fromHql = orgHql;
			//select子句与order by子句会影响count查询,进行简单的排除.
			fromHql = "from " + StringUtils.substringAfter(fromHql, "from");
			fromHql = StringUtils.substringBefore(fromHql, "order by");
			String countHql = "select count(*) " + fromHql;
			return countHql;
		}
		/**
		 * 设置分页参数到Query对象,辅助函数.
		 */
		protected Query setPageParameterToQuery(final Query q, final PageUtils<T> page) {
			Assert.isTrue(page.getPageSize() > 0, "Page Size must larger than zero");
			//hibernate的firstResult的序号从0开始
			q.setFirstResult(page.getFirst() - 1);
			q.setMaxResults(page.getPageSize());
			return q;
		}

}